package com.snbc.util;

import org.apache.zookeeper.KeeperException;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class ShardNumGenerate {
	   private static final int reserveDay=90;
	   private static final SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
	   public static void main(String[] args){
		   if(args.length<1){
			   System.out.println("ERROR,Usage:java -cp $path com.snbc.util.ShardNumGenerate 'host1:2181,host1:2181,host1:2181' [collectionName]");
			   System.exit(-1);
		   }
		   String zkHost=args[0];
		   String collectionName="bank-note-collection";
		   if(args.length==2){
			   collectionName=args[1];
		   }
		   try {
			   printShardsInfo(collectionName,zkHost);
		   } catch (IOException | InterruptedException | KeeperException e) {
				e.printStackTrace();
		   }
//		   int seqDay=getSeqDay("20180522");
//		   System.out.println(seqDay);
	   }
	   public static Map<String,String> printShardsInfo(String collectionName, String zkHost) throws IOException, InterruptedException, KeeperException{
		   Map<String,String> retMap = new HashMap<String,String>();
		   SolrUtil util=new SolrUtil(zkHost);
		   int nodes= util.getSolrLiveNodes();
		   List<String> shards=util.getCollectionShards(collectionName);
		   
		   int indexNum=getIndexNum(nodes);//12
		   String currentDay=getCurrentDay();
		   
		   int realSeqDay =getSeqDay(currentDay);//从1月1日  到现在多少天157
		   int seqNum=getSeqNum(realSeqDay,indexNum);//14
		   String currentSahrdName=getSeqNumShardName(shards,currentDay,nodes,indexNum);
		   
		   int shardSeqDay=indexNum*seqNum<=365?indexNum*seqNum:365;//168
		   int dis=shardSeqDay-realSeqDay;//11
		   
		   String afterDay=getDayBeforeOrAfter(currentDay,dis+1);//0618
		   String nextSahrdName=getSeqNumShardName(shards,afterDay,nodes,indexNum);//15
		   
		   String beforeDay=getDayBeforeOrAfter(afterDay,-(reserveDay-1));//0321
		   
		   
		   System.out.println("currentSahrdName="+currentSahrdName+",and "+dis+" days later,which after "
				   +afterDay+",then you had create a new shard named="+nextSahrdName+" in solr if it's not exists!");
		   retMap.put("nextShard", nextSahrdName);
		   
		   String delSahrdName=getSeqNumShardName(shards,beforeDay,nodes,indexNum);
		   System.out.println("shard collection is "+shards+" delete shard is "+delSahrdName);
		   retMap.put("deleteShard", delSahrdName);
		   if(shards.contains(delSahrdName)){
			   seqNum=getSeqNumByShardName(delSahrdName);
			   String nowYear=getNowYear();
			   String begin=getDayBeforeOrAfter(nowYear+"0101",(indexNum*(seqNum-1)+1));
			   String end=getDayBeforeOrAfter(nowYear+"0101",indexNum*seqNum<=365?indexNum*seqNum:365);
			   System.out.println("["+begin+","+end+"]");
			   System.out.println("the fisrt shard is "+delSahrdName+"["+begin+"["+end+"],it should be delete after the day "+end);
			   retMap.put("afterDay", afterDay);
		   }
		   return retMap;
	   }
	   /**
	    * shard_1620
	    * @param sahrdName
	    * @return
	    */
	   private static int getSeqNumByShardName(String sahrdName){
		   String seq=sahrdName.substring("shard_xx".length());
		   return Integer.parseInt(seq);
	   }
	   
	   public static String getDayBeforeOrAfter(String dateDay, int dayBefore){
		   String year=dateDay.substring(0,4);
		   String month=dateDay.substring(4, 6);
		   String day=dateDay.substring(6);
		   Calendar cal =  new GregorianCalendar(Integer.parseInt(year), Integer.parseInt(month)-1, Integer.parseInt(day),0,0,0);
		   cal.add(Calendar.DAY_OF_MONTH, dayBefore);
		   return sdf.format(cal.getTime());
	   }
	   public static int getIndexNum(int nodes){
		   nodes=nodes-1;
		   int mod=reserveDay%nodes;
		   return mod==0?reserveDay/nodes:(reserveDay/nodes+1);
	   }
	   private static String getCurrentDay(){
		   return sdf.format(new Date());
	   }
	   private static String getNowYear(){
		   String currentDay=getCurrentDay();
		   return currentDay.substring(0, 4);
	   }
	   
	   public static int getSeqNum(int seqDay,int indexNum){
		   int mod=seqDay%indexNum;
		   int seq=mod==0?seqDay/indexNum:(seqDay/indexNum+1);
		   return seq;
	   }
	   public static String getShardName(String collectionName, String dateDay){
		   Properties pro=PropertiesUtil.getPro();
		   SolrUtil util=new SolrUtil(pro.getProperty("zkhost"));
		   int nodes=9;
			try {
				nodes = util.getSolrLiveNodes();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (KeeperException e) {
				e.printStackTrace();
			}
		   int indexNum=getIndexNum(nodes);//12
		   List<String> shards=util.getCollectionShards(collectionName);
		   return getSeqNumShardName(shards,dateDay,nodes,indexNum);
	   }
	   public static String getSeqNumShardName(List<String> shards, String dateDay, int nodes, int indexNum){
		   int seqDay=getSeqDay(dateDay);
		   int seqNum=getSeqNum(seqDay,indexNum);
		   String shardName="shard_"+dateDay.substring(2, 4)+(seqNum<10?"0"+seqNum:seqNum);
		   
		   if(shards==null){
			   return shardName;
		   }
		   
		   if(shards.contains(shardName) && shards.size()<nodes-1){
			   return shardName;
		   }else{
			   List<String> usedSahrds=getUsedSards(shards,shardName);
			   if(usedSahrds.size()<nodes-1){
				   return shardName;
			   }else{
				   int dis2=seqNum*indexNum>=365?365-(seqNum-1)*indexNum:indexNum;
				   int dis1=indexNum-(seqDay-(seqNum-1)*indexNum);
				   if(dis1>dis2){
					   return "shard_"+dateDay.substring(2, 4)+(seqNum-1<10?"0"+(seqNum-1):seqNum-1);
				   }else{
					   return shardName;
				   }
			   }
		   }
	   }
	   private static List<String> getUsedSards(List<String> shards, String shardName){
		   List<String> usedShards=new ArrayList<String>();
		   for(String shard:shards){
			   if(shardName.compareTo(shard)>0){
				   usedShards.add(shard);
			   }else{
				   break;
			   }
		   }
		   return usedShards;
	   }
	   private static int getSeqDay(String dateDay){
		    if(!matchDay(dateDay)){
			   dateDay=getCurrentDay();
		    }
		    int count = 0;	       
		   	int days = 0;
	       
	        int year= Integer.parseInt(dateDay.substring(0, 4));
	        int month= Integer.parseInt(dateDay.substring(4, 6));
	        int day= Integer.parseInt(dateDay.substring(6));
	        if (year > 0 && month > 0 && month < 13 && day > 0 && day < 32) {
	            for (int i = 1; i < month; i++) {
	                switch (i) {
	                case 1:
	                case 3:
	                case 5:
	                case 7:
	                case 8:
	                case 10:
	                case 12:
	                    days = 31;
	                    break;
	                case 4:
	                case 6:
	                case 9:
	                case 11:
	                    days = 30;
	                    break;
	                case 2: {
	                    if ((year % 4 == 0 && year % 1 != 0) || (year % 400 == 0)) {
	                        days = 29;
	                    } else {
	                        days = 28;
	                    }
	                    break;
	                }
	                }
	                count = count + days;
	            }
	            count = count + day;
	        }
	        return count;
	   }
	   private static boolean matchDay(String str){
			SimpleDateFormat formater=new SimpleDateFormat("yyyyMMdd");
			try {
				Date d=formater.parse(str);
				return str.equals(formater.format(d));
			} catch (ParseException e) {
				e.printStackTrace();
				return false;
			}
		}
}

 
